-- Task class, stores all related info regarding tasks --'************************************************************************************* --' Descriptor for an ordinary job --'************************************************************************************* local guiders_by_level = { ["zaton"]={["jupiter"]="zat_b215_stalker_guide_zaton", ["pripyat"]="zat_b215_stalker_guide_zaton"}, ["jupiter"]={["zaton"]="zat_b215_stalker_guide_jupiter", ["pripyat"]="jup_b43_stalker_assistant"}, ["pripyat"]={["zaton"]="jup_b43_stalker_assistant_pri", ["jupiter"]="jup_b43_stalker_assistant_pri"}, } function get_guider(target_level) local ln = level.name() if(guiders_by_level[ln] and guiders_by_level[ln][target_level]) then return get_story_object_id(guiders_by_level[ln][target_level]) end return nil end --[[ C++ class task { const additional = 1; const completed = 2; const fail = 0; const in_progress = 1; const insignificant = 2; const storyline = 0; const task_dummy = 65535; }; ]] class "CGeneralTask" function CGeneralTask:__init(id) self.loaded = false local task_ini = task_manager.task_ini self.id = id self.stage = 0 self.title = task_ini:r_string_ex(id,"title") or "TITLE_DOESNT_EXIST" self.title_functor = task_ini:r_string_ex(id,"title_functor") or "condlist" self.current_title = nil self.descr = task_ini:r_string_ex(id,"descr") or "DESCR_DOESNT_EXIST" self.descr_functor = task_ini:r_string_ex(id,"descr_functor") or "condlist" self.current_descr = nil self.target = task_ini:r_string_ex(id,"target") self.target_functor = task_ini:r_string_ex(id,"target_functor") or "target_condlist" self.status_functor = task_ini:r_string_ex(id,"status_functor") self.current_target = nil self.icon = task_ini:r_string_ex(id,"icon") or "ui_pda2_mtask_overlay" self.prior = task_ini:r_float_ex(id,"prior") or 0 self.storyline = task_ini:r_bool_ex(id,"storyline",false) self.repeat_timeout = task_ini:r_float_ex(id,"repeat_timeout") self.timeout = nil --' Terms of execution and failure of the quest local i = 0 self.condlist = {} while task_ini:line_exist(id, "condlist_"..i) do local clst = task_ini:r_string_to_condlist(id,"condlist_"..i) if (clst) then table.insert(self.condlist,clst) end i = i + 1 end --' Condelists on the status quests self.on_init = task_ini:r_string_to_condlist(id,"on_init") self.on_complete = task_ini:r_string_to_condlist(id,"on_complete") self.on_fail = task_ini:r_string_to_condlist(id,"on_fail") self.on_reversed = task_ini:r_string_to_condlist(id,"on_reversed") self.on_cancel = task_ini:r_string_to_condlist(id,"on_cancel") --' Quest Rewards -- IMPORTANT ONLY USE THESE WHEN YOU COMPLETE TASK WHILE IN DIALOG!!! self.reward_money = task_ini:r_string_to_condlist(id,"reward_money") self.reward_item = task_ini:r_string_to_condlist(id,"reward_money") --' Статус квеста, может быть: "normal", "selected", "completed", "fail", "reversed" self.status = "normal" self.current_title = db.actor and task_functor[self.title_functor](self.id, "title", self.title,self) self.current_descr = db.actor and task_functor[self.descr_functor](self.id, "descr", self.descr,self) local time = 0 if self.wait_time ~= nil then time = self.wait_time -- Here the time is specified in game seconds end if(self.storyline) then if time == 0 then self.spot = "storyline_task_location" else self.spot = "storyline_task_location_complex_timer" end local ttl = self.current_title and game.translate_string(self.current_title) if ttl then local msg = game.translate_string("general_new_task") .. " " .. ttl actor_menu.set_fade_msg( msg, 5, nil, "interface\\horror_notify_02" ) -- Fading text end else if time == 0 then self.spot = "secondary_task_location" else self.spot = "secondary_task_location_complex_timer" end end if (self.target_functor == nil or task_functor[self.target_functor] == nil) then printf("task_id=%s | target_functor not set properly, it's either missing or misnamed, check tm_*.ltx and task_functor.script",id) end self.current_target = db.actor and self.target_functor and task_functor[self.target_functor](self.id, "target", self.target,self) self.dont_send_update_news = task_ini:r_bool_ex(id,"dont_send_update_news",false) end function CGeneralTask:get_title() return self.title or "" end function CGeneralTask:get_icon_name() return self.icon end --' Issue of quest function CGeneralTask:give_task() local t = db.actor and db.actor:get_task(self.id, true) or CGameTask() t:set_id(tostring(self.id)) if(self.storyline) then t:set_type(task.storyline) else t:set_type(task.additional) end t:set_title(self.current_title) t:set_description(self.current_descr) t:set_priority(self.prior) t:set_icon_name(self.icon) t:add_complete_func("task_manager.task_complete") t:add_fail_func("task_manager.task_fail") if (self.on_init) then xr_logic.pick_section_from_condlist(db.actor, db.actor, self.on_init) end if self.current_target ~= nil then t:set_map_location(self.spot) t:set_map_object_id(self.current_target) if(self.storyline) then level.map_add_object_spot(self.current_target, "ui_storyline_task_blink", "") else level.map_add_object_spot(self.current_target, "ui_secondary_task_blink", "") end end local time = 0 if self.wait_time ~= nil then time = self.wait_time -- Here the time is specified in game seconds end --' Заносим в task_info self.status = "selected" self.inited_time = game.get_game_time() db.actor:give_task(t, time*10, false, time) self.t = t self.stage = 0 self.forced_status = nil end --' Checking the current execution of the quest function CGeneralTask:check_task(tm) local tg = time_global() if (self.check_time and self.last_check_task == nil and tg < self.check_time) then return end if (not db.actor) then return end self.t = self.t or db.actor and db.actor:get_task(self.id,true) if (self.t == nil) then -- task is most likely in timeout return end self.check_time = tg + math.random(500,1000) --+ (self.prior*10) local task_updated = false local t_tile = task_functor[self.title_functor](self.id, "title", self.title, self) if self.current_title ~= t_tile then --printf("task [%s] updated due to title change from [%s] to [%s]", tostring(self.id), tostring(self.current_title), tostring(t_tile)) task_updated = true self.current_title = t_tile self.t:set_title(game.translate_string(t_tile)) end local t_descr = task_functor[self.descr_functor](self.id, "descr", self.descr, self) if self.current_descr ~= t_descr then --printf("task [%s] updated due to description change from [%s] to [%s]", tostring(self.id), tostring(self.current_descr), tostring(t_descr)) task_updated = true self.current_descr = t_descr self.t:set_description(game.translate_string(t_descr)) end local t_target = task_functor[self.target_functor](self.id, "target", self.target, self) self:check_level(t_target) --printf("%s map_location=%s id=%s target=%s",self.current_title,self.t:get_map_location(),self.t:get_map_object_id(),t_target) if (self.current_target ~= t_target) then task_updated = true if (t_target == nil) then self.t:remove_map_locations(false) else self.t:change_map_location(self.spot, t_target) if(self.storyline) then level.map_add_object_spot(t_target, "ui_storyline_task_blink", "") else level.map_add_object_spot(t_target, "ui_secondary_task_blink", "") end end self.current_target = t_target end if task_updated and not(self.dont_send_update_news) then news_manager.send_task(db.actor, "updated", self.t) end for k,v in pairs(self.condlist) do local t = xr_logic.pick_section_from_condlist(db.actor, db.actor, v) if (t) and (t == "complete" or t == "fail" or t == "reversed") then self.last_check_task = t return end end -- status functor if (self.status_functor and task_status_functor[self.status_functor]) then local t = task_status_functor[self.status_functor](self,self.id) if (t) and (t == "complete" or t == "fail" or t == "reversed") then self.last_check_task = t end end end --' Initializing the reward function CGeneralTask:give_reward() local money = self.reward_money and xr_logic.pick_section_from_condlist(db.actor, db.actor, self.reward_money) local items = self.reward_item and xr_logic.pick_section_from_condlist(db.actor, db.actor, self.reward_item) -- Награду можно выдать двумя методами: от нпс или просто свалитьс неба. Если не найден НПС, с которым мы в диалоге, то просто валим с неба local npc = get_speaker() if not (npc) then return end if money ~= nil then dialogs.relocate_money(npc, tonumber(money), "in") end if items ~= nil then local ancillary_item_table = {} for k,v in pairs(parse_names(items)) do if ancillary_item_table[v] == nil then ancillary_item_table[v] = 1 else ancillary_item_table[v] = ancillary_item_table[v] + 1 end end for k,v in pairs(ancillary_item_table) do dialogs.relocate_item_section(npc, k, "in", v) end end end function CGeneralTask:reverse_task() self.last_check_task = "reversed" end --' Deactivation of the quest function CGeneralTask:deactivate_task(tsk) --printf("deactivate task %s", self.id) self.check_time = nil if self.last_check_task == "fail" then if (self.on_fail) then xr_logic.pick_section_from_condlist(db.actor, db.actor, self.on_fail) end news_manager.send_task(db.actor, "fail", tsk) elseif self.last_check_task == "reversed" then if (self.on_reversed) then xr_logic.pick_section_from_condlist(db.actor, db.actor, self.on_reversed) end news_manager.send_task(db.actor, "reversed", tsk) end self.last_check_task = nil self.status = "normal" end function CGeneralTask:check_level(target) if not(db.actor:is_active_task(self.t)) or not(target) then return end if not(level) then return end local s_obj = alife_object(target) if(s_obj) then local target_level = alife():level_name(game_graph():vertex(s_obj.m_game_vertex_id):level_id()) local level_name = level.name() if(level_name~=target_level) then local guider_id = get_guider(target_level) if not(guider_id) then return end local guider_spot = "" local guider_spot2 = "" if(self.storyline) then guider_spot = "storyline_task_on_guider" guider_spot2 = "secondary_task_on_guider" else guider_spot = "secondary_task_on_guider" guider_spot2 = "storyline_task_on_guider" end if(level.map_has_object_spot(guider_id, guider_spot2)~=0) then level.map_remove_object_spot(guider_id, guider_spot2) end if(guider_id and level.map_has_object_spot(guider_id, guider_spot)==0) then level.map_add_object_spot(guider_id, guider_spot, "") end else self:remove_guider_spot() end end end function CGeneralTask:remove_guider_spot(target) if not(guiders_by_level[level.name()]) then return end for k,v in pairs(guiders_by_level[level.name()]) do local guider_id = get_story_object_id(v) if(guider_id) then if(level.map_has_object_spot(guider_id, "storyline_task_on_guider")~=0) then level.map_remove_object_spot(guider_id, "storyline_task_on_guider") end if(level.map_has_object_spot(guider_id, "secondary_task_on_guider")~=0) then level.map_remove_object_spot(guider_id, "secondary_task_on_guider") end end end end -- Save quest function CGeneralTask:save(packet) if (USE_MARSHAL) then return end local id_by_status = { ["normal"] = 0, ["selected"] = 1, ["completed"] = 2, ["fail"] = 3, ["reversed"] = 4 } --set_save_marker(packet, "save", false, "CGeneralTask") utils_data.w_stpk(packet,"u8",id_by_status[self.status] or 0,"CGeneralTask:id_by_status") if (self.status == "completed" or self.status == "fail") then if (self.repeat_timeout) then utils_data.w_stpk(packet,"CTime",self.timeout,"CGeneralTask:repeat_timeout") end return end utils_data.w_stpk(packet,"CTime",self.inited_time,"CGeneralTask:inited_time") utils_data.w_stpk(packet,"stringZ",self.current_title,"CGeneralTask:current title") utils_data.w_stpk(packet,"stringZ",self.current_descr,"CGeneralTask:current descr") utils_data.w_stpk(packet,"stringZ",tostring(self.current_target),"CGeneralTask:current target") utils_data.w_stpk(packet,"stringZ",tostring(self.task_giver_id),"CGeneralTask:task giver id") utils_data.w_stpk(packet,"u8",self.stage,"CGeneralTask:current stage") --set_save_marker(packet, "save", true, "CGeneralTask") end -- Load quest function CGeneralTask:load(packet) if (USE_MARSHAL) then return end local status_by_id = { [0] = "normal", [1] = "selected", [2] = "completed", [3] = "fail", [4] = "reversed" } --set_save_marker(packet, "load", false, "CGeneralTask") self.status = status_by_id[packet:r_u8()] if (self.status == "completed" or self.status == "fail") then if (self.repeat_timeout) then self.timeout = utils_data.r_CTime(packet) or game.get_game_time() end return end self.inited_time = utils_data.r_CTime(packet) or game.get_game_time() self.current_title = packet:r_stringZ() self.current_descr = packet:r_stringZ() self.current_target = packet:r_stringZ() self.task_giver_id = packet:r_stringZ() self.stage = packet:r_u8() self.current_target = self.current_target == "nil" and nil or tonumber(self.current_target) self.task_giver_id = self.task_giver_id == "nil" and nil or tonumber(self.task_giver_id) --set_save_marker(packet, "load", true, "CGeneralTask") end function CGeneralTask:save_state(m_data) --utils_data.debug_write(strformat("CGeneralTask:save_state %s BEFORE",self.id)) if (self.t == nil) then if (self.repeat_timeout == nil or self.timeout == nil) then return end if (game.get_game_time():diffSec(self.timeout) > self.repeat_timeout) then return end end m_data.task_objects[self.id] = {} m_data.task_objects[self.id].status = self.status m_data.task_objects[self.id].timeout = self.timeout m_data.task_objects[self.id].inited_time = self.inited_time m_data.task_objects[self.id].current_title = self.current_title m_data.task_objects[self.id].current_descr = self.current_descr m_data.task_objects[self.id].current_target = self.current_target m_data.task_objects[self.id].stage = self.stage m_data.task_objects[self.id].task_giver_id = self.task_giver_id --utils_data.debug_write(strformat("CGeneralTask:save_state %s AFTER",self.id)) end function CGeneralTask:load_state(m_data) if not (m_data.task_objects and m_data.task_objects[self.id]) then return false end --utils_data.debug_write(strformat("CGeneralTask:load_state %s BEFORE",self.id)) self.status = m_data.task_objects[self.id].status self.timeout = m_data.task_objects[self.id].timeout self.inited_time = m_data.task_objects[self.id].inited_time self.current_title = m_data.task_objects[self.id].current_title self.current_descr = m_data.task_objects[self.id].current_descr self.current_target = m_data.task_objects[self.id].current_target self.stage = m_data.task_objects[self.id].stage self.task_giver_id = m_data.task_objects[self.id].task_giver_id m_data.task_objects[self.id] = nil self.loaded = true --utils_data.debug_write(strformat("CGeneralTask:load_state %s AFTER",self.id)) return true end